package com.gun.management.module.raffle.service.lottery;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.gun.management.framework.common.exception.ServiceException;
import com.gun.management.framework.common.pojo.PageResult;
import com.gun.management.framework.common.util.object.BeanUtils;
import com.gun.management.framework.web.core.util.WebFrameworkUtils;
import com.gun.management.module.raffle.controller.admin.lottery.vo.LotteryPageReqVO;
import com.gun.management.module.raffle.controller.admin.lottery.vo.LotterySaveReqVO;
import com.gun.management.module.raffle.controller.admin.lotteryrule.vo.LotteryRuleSaveReqVO;
import com.gun.management.module.raffle.controller.admin.lotteryrule.vo.LotteryRuleSetVO;
import com.gun.management.module.raffle.dal.dataobject.lottery.LotteryDO;
import com.gun.management.module.raffle.dal.dataobject.lotteryrule.LotteryRuleDO;
import com.gun.management.module.raffle.dal.dataobject.lotteryruleref.LotteryRuleRefDO;
import com.gun.management.module.raffle.dal.mysql.lottery.LotteryMapper;
import com.gun.management.module.raffle.dal.mysql.lotteryrule.LotteryRuleMapper;
import com.gun.management.module.raffle.dal.mysql.lotteryruleref.LotteryRuleRefMapper;
import com.gun.management.module.raffle.enums.ErrorCodeConstants;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;

import jakarta.annotation.Resource;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

import static com.gun.management.framework.common.exception.util.ServiceExceptionUtil.exception;

/**
 * 抽奖信息 Service 实现类
 *
 * @author 测试账号
 */
@Service
@Validated
public class LotteryServiceImpl implements LotteryService {

    @Resource
    private LotteryMapper lotteryMapper;

    @Resource
    private LotteryRuleMapper lotteryRuleMapper;

    @Resource
    private LotteryRuleRefMapper lotteryRuleRefMapper;

    public final static int LOTTERY_NOT_EXISTS = 401;

    @Override
    @Transactional(rollbackFor = Throwable.class)
    public Long createLottery(LotterySaveReqVO createReqVO) {

        LambdaQueryWrapper<LotteryDO> lambdaQueryWrapper = Wrappers.lambdaQuery();
        lambdaQueryWrapper.eq(LotteryDO::getName, createReqVO.getName());
        LotteryDO lotteryDO = lotteryMapper.selectOne(lambdaQueryWrapper);
        if (lotteryDO != null) {
            throw new ServiceException(408, createReqVO.getName() + "已存在,不允许重复添加!");
        }

//        if(createReqVO.getMaxPrizeCount() != 0 && createReqVO.getMaxPrizeCount() != createReqVO.getRuleList().size()) {
//            throw new ServiceException(802,"列表中奖品总数量必须等于限制添加奖品的数量!");
//        }

        if (createReqVO.getTotalTimes() < createReqVO.getDayTotalTimes()) {
            throw new ServiceException(802, "每人抽奖总次数不能小于每人每天抽奖次数");
        }

        if (hasDuplicateIds(createReqVO.getRuleList())) {
            throw new ServiceException(803, "选择的奖品列表不允许有重复的奖品!");
        }


        Integer sumPrizeProbability = 0;

        Long userId = WebFrameworkUtils.getLoginUserId();

        List<LotteryRuleDO> lotteryRuleDOList = new ArrayList<>();
        for (LotteryRuleSaveReqVO item : createReqVO.getRuleList()) {
            sumPrizeProbability += item.getPrizeProbability();

            LotteryRuleDO lotteryRuleDO = new LotteryRuleDO();

            lotteryRuleDO.setProductId(item.getProductId());
            lotteryRuleDO.setSkuId(item.getSkuId());
            lotteryRuleDO.setName(item.getName());
            lotteryRuleDO.setAvatar(item.getAvatar());
            lotteryRuleDO.setCategoryId(item.getCategoryId());
            lotteryRuleDO.setPrizeQty(item.getPrizeQty());
            lotteryRuleDO.setPrompt(item.getPrompt());
            lotteryRuleDO.setPrizeProbability(item.getPrizeProbability()); 

            lotteryRuleDO.setCreator(String.valueOf(userId));
            lotteryRuleDO.setCreateTime(LocalDateTime.now());


            lotteryRuleDOList.add(lotteryRuleDO);
        }
        if (sumPrizeProbability != 100) {
            throw new ServiceException(802, "奖品抽奖总概率值不等于100,请重新配置后再试!");
        }

        // 1.插入
        LotteryDO lottery = BeanUtils.toBean(createReqVO, LotteryDO.class);
        lottery.setStatus(1);  // 新插入的抽奖活动，默认是禁用的，免得影响其它活动
        lottery.setCreator(String.valueOf(userId));
        lottery.setCreateTime(LocalDateTime.now());
        lottery.setBgPicture(createReqVO.getBgPicture());


        lotteryMapper.insertAndGetId(lottery);

        // 2.创建抽奖活动-奖品表关联
        // List<LotteryRuleRefDO>  lotteryRuleRefList = new ArrayList();
        for (LotteryRuleDO lotteryRuleDO : lotteryRuleDOList) {

            // 插入奖品(规则)
            lotteryRuleDO.setStatus(0);  // 默认奖品状态为启用状态
            lotteryRuleDO.setCreator(String.valueOf(userId));
            lotteryRuleDO.setCreateTime(LocalDateTime.now());

            lotteryRuleMapper.insertAndGetId(lotteryRuleDO);

            LotteryRuleRefDO lotteryRuleRefDO = new LotteryRuleRefDO();
            lotteryRuleRefDO.setLotteryId(lottery.getId());
            lotteryRuleRefDO.setRuleId(lotteryRuleDO.getId());

            lotteryRuleRefMapper.insertAndGetId(lotteryRuleRefDO);
        }


        // 返回
        return lottery.getId();
    }

    @Override
    @Transactional(rollbackFor = Throwable.class)
    public void updateLottery(LotterySaveReqVO updateReqVO) {
        if (updateReqVO.getTotalTimes() < updateReqVO.getDayTotalTimes()) {
            throw new ServiceException(801, "每人抽奖总次数不能小于每人每天抽奖次数");
        }

        if (updateReqVO.getMaxPrizeCount() != 0 && updateReqVO.getMaxPrizeCount() != updateReqVO.getRuleList().size()) {
            throw new ServiceException(802, "列表中奖品总数量必须等于限制添加奖品的数量!");
        }

        if (hasDuplicateIds(updateReqVO.getRuleList())) {
            throw new ServiceException(803, "选择的奖品列表不允许有重复的奖品!");
        }


        Long userId = WebFrameworkUtils.getLoginUserId();
        Integer sumPrizeProbability = 0;
        List<LotteryRuleDO> lotteryRuleDOList = new ArrayList<>();
        for (LotteryRuleSaveReqVO item : updateReqVO.getRuleList()) {
            sumPrizeProbability += item.getPrizeProbability();

            LotteryRuleDO lotteryRuleDO = new LotteryRuleDO();

            lotteryRuleDO.setId(item.getId());
            lotteryRuleDO.setProductId(item.getProductId());
            lotteryRuleDO.setSkuId(item.getSkuId());
            lotteryRuleDO.setName(item.getName());
            lotteryRuleDO.setAvatar(item.getAvatar());
            lotteryRuleDO.setCategoryId(item.getCategoryId());
            lotteryRuleDO.setPrizeQty(item.getPrizeQty());
            lotteryRuleDO.setPrompt(item.getPrompt());
            lotteryRuleDO.setPrizeProbability(item.getPrizeProbability());

            lotteryRuleDO.setCreator(String.valueOf(userId));
            lotteryRuleDO.setCreateTime(LocalDateTime.now());

            lotteryRuleDOList.add(lotteryRuleDO);
        }

        if (sumPrizeProbability != 100) {
            throw new ServiceException(802, "奖品抽奖总概率值不等于100,请重新配置后再试!");
        }
        // 校验存在
        validateLotteryExists(updateReqVO.getId());
        // 1.更新
        LotteryDO updateObj = BeanUtils.toBean(updateReqVO, LotteryDO.class);

        updateObj.setUpdater(String.valueOf(userId));
        updateObj.setUpdateTime(LocalDateTime.now());
        updateObj.setBgPicture(updateObj.getBgPicture()); // 添加抽奖活动背景图

        lotteryMapper.updateById(updateObj);

        List<Long> ruleIdList = updateReqVO.getRuleList().stream().map(LotteryRuleSaveReqVO::getId).collect(Collectors.toList());

        // 2.批量删除之前创建好的关联
        LambdaQueryWrapper<LotteryRuleRefDO> lotteryRuleRefLambdaQueryWrapper = Wrappers.lambdaQuery();
        lotteryRuleRefLambdaQueryWrapper.eq(LotteryRuleRefDO::getLotteryId, updateReqVO.getId());

        // 先删除
        lotteryRuleRefMapper.delete(lotteryRuleRefLambdaQueryWrapper);

        // 3.创建抽奖活动-奖品表关联
        for (LotteryRuleDO lotteryRuleDO : lotteryRuleDOList) {

            // 插入奖品(规则)
            lotteryRuleDO.setStatus(0);

            lotteryRuleDO.setCreator(String.valueOf(userId));
            lotteryRuleDO.setCreateTime(LocalDateTime.now());

            lotteryRuleMapper.insertAndGetId(lotteryRuleDO);

            LotteryRuleRefDO lotteryRuleRefDO = new LotteryRuleRefDO();
            lotteryRuleRefDO.setLotteryId(updateObj.getId());
            lotteryRuleRefDO.setRuleId(lotteryRuleDO.getId()); // 获取到新的id

            lotteryRuleRefMapper.insertAndGetId(lotteryRuleRefDO);
        }
    }

    /**
     * 判断列表中是否有重复的商品
     *
     * @param list
     * @return
     */
    private boolean hasDuplicateIds(List<LotteryRuleSaveReqVO> list) {
        Set<LotteryRuleSetVO> productSkuIds = new HashSet();

        for (LotteryRuleSaveReqVO item : list) {
            LotteryRuleSetVO lotteryRuleSetVO = new LotteryRuleSetVO(item.getProductId(), item.getSkuId());
            if (productSkuIds.contains(lotteryRuleSetVO)) {
                return true;
            }
            productSkuIds.add(lotteryRuleSetVO);
        }
        return false; // 如果循环完成没有返回true，说明没有重复
    }


    @Override
    public void deleteLottery(Long id) {
        // 校验存在
        validateLotteryExists(id);
        // 删除
        lotteryMapper.deleteById(id);
    }

    private void validateLotteryExists(Long id) {
        if (lotteryMapper.selectById(id) == null) {
            throw exception(ErrorCodeConstants.LOTTERY_NOT_EXISTS);
        }
    }

    @Override
    public LotteryDO getLottery(Long id) {
        return lotteryMapper.selectById(id);
    }

    @Override
    public PageResult<LotteryDO> getLotteryPage(LotteryPageReqVO pageReqVO) {
        return lotteryMapper.selectPage(pageReqVO);
    }

    @Override
    public List<LotteryDO> getLotteryListByStatus(Integer status) {
        return lotteryMapper.selectListByStatus(status);
    }

    @Override
    @Transactional(rollbackFor = Throwable.class)
    public void updateStatusEnabled(Long id, Long categoryId, Boolean enabled) {
        // 校验存在
        validateLotteryExists(id);
        Long userId = WebFrameworkUtils.getLoginUserId();
        // 1.把所有启用的均改成禁用
        if (enabled == false) {
            LambdaUpdateWrapper<LotteryDO> lambdaUpdateWrapper1 = new LambdaUpdateWrapper();
            lambdaUpdateWrapper1.eq(LotteryDO::getStatus, 0);
            lambdaUpdateWrapper1.eq(LotteryDO::getCategoryId, categoryId);
            lambdaUpdateWrapper1.set(LotteryDO::getStatus, 1);

            lambdaUpdateWrapper1.set(LotteryDO::getUpdater, userId);
            lambdaUpdateWrapper1.set(LotteryDO::getUpdateTime, LocalDateTime.now());
            lotteryMapper.update(null, lambdaUpdateWrapper1);
        }

        LambdaUpdateWrapper<LotteryDO> lambdaUpdateWrapper2 = new LambdaUpdateWrapper();
        lambdaUpdateWrapper2.eq(LotteryDO::getId, id);
        lambdaUpdateWrapper2.set(LotteryDO::getStatus, enabled ? 1 : 0);

        lambdaUpdateWrapper2.set(LotteryDO::getUpdater, userId);
        lambdaUpdateWrapper2.set(LotteryDO::getUpdateTime, LocalDateTime.now());
        lotteryMapper.update(null, lambdaUpdateWrapper2);
    }


}
